package xyz.eden.gateway.springcloud.admin.component.route.nacos;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import xyz.eden.gateway.springcloud.admin.component.route.AbstractDynamicRouteService;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.Executor;

@Slf4j
@Service
@DependsOn(value = {"nacosDataSourceProperties"})
public class DynamicRouteServiceByNacos extends AbstractDynamicRouteService {

    private ConfigService configService;

    @Resource
    private NacosDataSourceProperties dataSourceProperties;


    @Override
    protected boolean prefixOperation() {
        log.info("[Dynamic Route By Nacos] prefix Operation begin.");
        ConfigService newConfigService = this.createConfigService();
        if (Objects.isNull(newConfigService)) {
            log.info("[Dynamic Route By Nacos] Create ConfigService, Result is null.");
            return false;
        }

        this.configService = newConfigService;
        return true;
    }

    @Override
    protected boolean postOperation() {
        boolean result = this.registerConfigChangeListener();
        log.error("[Dynamic Route By Nacos] register Config Change Listener, Result: [{}].", result);
        return result;
    }

    private boolean registerConfigChangeListener() {
        try {
            this.configService.addListener(dataSourceProperties.getDataId(), dataSourceProperties.getGroup(), new Listener() {
                @Override
                public Executor getExecutor() {
                    return null;
                }

                @Override
                public void receiveConfigInfo(String configInfo) {
                    log.info("[Dynamic Route By Nacos] receive configInfo: [{}].", configInfo);
                    List<RouteDefinition> list = NacosTool.builderRouteDefinition(configInfo);
                    boolean result = handleRouteConfigInfo(list);
                    log.info("[Dynamic Route By Nacos] receive configInfo, result: [{}].", result);
                }
            });
            return true;
        } catch (Exception e) {
            log.error("[Dynamic Route By Nacos] receive configInfo exception");
            return false;
        }
    }

    @Override
    public List<RouteDefinition> getRouteDefinitionConfig() {
        try {
            String configInfo = this.configService.getConfig(dataSourceProperties.getDataId(), dataSourceProperties.getGroup(), dataSourceProperties.getTimeout());
            return NacosTool.builderRouteDefinition(configInfo);
        } catch (NacosException e) {
            log.error("[Dynamic Route By Nacos] get routeDefinition Exception, msg: [{}].", e.getMessage(), e);
            throw new RuntimeException("Get RouteDefinition Exception");
        }
    }

    /**
     * 创建配置服务
     *
     * @return
     */
    private ConfigService createConfigService() {
        try {
            Properties properties = new Properties();
            properties.setProperty(NacosServiceConstant.ServiceProperties.SERVER_ADDR, dataSourceProperties.getServerAddr());
            properties.setProperty(NacosServiceConstant.ServiceProperties.NAMESPACE, dataSourceProperties.getNamespace());
            return configService = NacosFactory.createConfigService(properties);
        } catch (Exception e) {
            log.error("[Dynamic Route By Nacos] create configService Exception, msg: [{}].", e.getMessage(), e);
            throw new RuntimeException("create ConfigService Exception");
        }
    }
}
